Imports WRDB.Controls

''' <summary>
''' Contains grid with some data to indicate which Working or Master data table is currently active
''' </summary>
''' <remarks>Also used to display all selected data</remarks>
Public Class frmBrowser
    Inherits System.Windows.Forms.Form

    Private MyFileName As String
    Private MyTableName As String                'tablename for Dataset
    Private MyTableFile As String                'just filename (no path)
    Private MyTableType As clsProject.enumTableTypes
    Private MyDataReader As DbDataReader
    Private MyAllowEditing As Boolean
    Private MyRecordCount As Long
    Private MyFormCaption As String
    Private MyTableIsView As Boolean = False
    Const EditCaption = " (Now Editing)"

    Private WithEvents bwGetDataSource As System.ComponentModel.BackgroundWorker
    Private FilterString As String
    Private MaxRecords As Integer = 1000
    Friend FillIsComplete As Boolean = True

    Private WithEvents dgvBrowser As WRDB.Controls.DGVEditor
    Private dtBrowser As DataTable
    Private daBrowser As DbDataAdapter
    Private HasBlob As Boolean = False

    Friend SqlString As String = ""
    Friend lstSortFields As New Generic.List(Of String) 'contains fields that have been chosen for sorting
    Private dictSigFigs As New Generic.Dictionary(Of String, Integer) 'contains PCode and number of significant figures for formatting

    Friend arFilters(14) As String

    <CLSCompliant(False)> _
    Public Sub New(TableName As String, TableType As clsProject.enumTableTypes, Optional FormCaption As String = "")
        Me.New()
        MyTableName = TableName
        MyTableType = TableType
        MyFormCaption = FormCaption
        Select Case TableType
            Case clsProject.enumTableTypes.Temporary : MyTableName = clsProject.TempData
            Case clsProject.enumTableTypes.Master : MyTableName = Project.MasterTableName
        End Select
        MyTableIsView = Project.DB.ViewExists(MyTableName)
        SetCaption()
    End Sub

    ''' <summary>
    ''' Returns full table name, qualified with brackets, suitable for SQL query
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    Friend ReadOnly Property FullTableName() As String
        Get
            If MyTableIsView Then 'to work with Oracle where views are in username schema and tables in database schema
                Return MyTableName
            Else
                Return Project.FullTableName(MyTableName)
            End If
        End Get
    End Property

    Friend ReadOnly Property FullFileName() As String
        Get
            Return MyFileName
        End Get
    End Property

    ''' <summary>
    ''' When the data in a browser table changes the associated selected records browser should be closed
    ''' </summary>
    ''' <remarks></remarks>
    Friend Sub CloseSelectedRecordsBrowser()
        'if current browser being closed was last used to query records shown in selected records browser, close that one too
        If MyTableType = clsProject.enumTableTypes.Temporary Then Exit Sub
        Dim IsLastSelectedTable As Boolean = (clsApplicationSettings.GetKey(enumKey.LastQueryTable, Project.TableName(MyTableName)) = MyTableName)
        For Each frm As Form In WRDBForms
            If TypeOf (frm) Is frmBrowser AndAlso CType(frm, frmBrowser).MyTableType = clsProject.enumTableTypes.Temporary AndAlso IsLastSelectedTable Then
                frm.Close()
                Exit For
            End If
        Next
        ActiveBrowser = Me
        If MainForm IsNot Nothing Then MainForm.EnableBrowserMenus()
    End Sub

    Friend ReadOnly Property TableName() As String
        Get
            Return MyTableName
        End Get
    End Property

    Friend ReadOnly Property TableType() As clsProject.enumTableTypes
        Get
            Return MyTableType
        End Get
    End Property

    ''' <summary>
    ''' Once the browser is open, if using subselects may need to reset the "tablename" which really contains the query string
    ''' </summary>
    ''' <param name="SQLString">Subselect SQL string</param>
    Friend Sub ResetQueryString(SQLString As String)
        MyTableName = SQLString
        FillGrid()
    End Sub

    Friend Sub PrintGrid()
        With New WRDB.Controls.DGVPrinter(dgBrowser, PrintDoc)
            .PrintDataGridView(True)
        End With
    End Sub

    Friend Property ShowAllOwnerRecords As Boolean

    Friend Property AllowEditing() As Boolean
        Get
            Return MyAllowEditing
        End Get
        Set(value As Boolean)
            MyAllowEditing = value
            If MyAllowEditing Then 'allow editing in grid
                mnuOptionsDropdowns.Visible = True
                mnuOptionsDelete.Visible = True
                mnuOptionsAppend.Visible = True
                With cboNumRecords
                    .Text &= EditCaption
                End With
            Else 'save the previous edits back to the table
                mnuOptionsDropdowns.Visible = False
                mnuOptionsDelete.Visible = False
                mnuOptionsAppend.Visible = False
                With cboNumRecords
                    Dim Cancel As Boolean = False
                    SaveEdits(Cancel)
                    If Cancel Then
                        MainForm.mnuEditGrid.Checked = True
                        MyAllowEditing = True
                        Exit Property
                    Else
                        MyAllowEditing = False
                        .Enabled = True
                        Text = Text.Replace(EditCaption, "")
                    End If
                End With
                'if selected records browser is open and associated with this table, update it also
                CloseSelectedRecordsBrowser()

            End If
            UpdateNumRecords()
            'FillGridInBackground()
            FinishFillGrid()
        End Set
    End Property

    Friend Sub SaveEdits(Optional ByRef Cancel As Boolean = False)
        Try
            dgBrowser.EndEdit()
            If dtBrowser IsNot Nothing AndAlso dtBrowser.GetChanges IsNot Nothing AndAlso dtBrowser.GetChanges.Rows.Count > 0 Then
                Select Case MessageBox.Show(String.Format("You have changed {0} record{1} in this browser. Do you want to save your changes back to the table?", dtBrowser.GetChanges.Rows.Count, IIf(dtBrowser.GetChanges.Rows.Count = 1, "", "s")), "Save Edits", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question)
                    Case Windows.Forms.DialogResult.Yes
                        dgBrowser.EndEdit()

                        'look at each records and make some updates...

                        'get next available RecID in case rows were added
                        Dim NextRecID As Integer = TestNull(Project.DB.ExecuteScalar("SELECT MAX(RecID) FROM {0}", FullTableName), 0) + 1

                        For Each row As DataRow In dtBrowser.Rows
                            'if records was changed, update the timestamp for the record (but don't update the owner unless it is null)
                            If row.RowState = DataRowState.Added Or row.RowState = DataRowState.Modified Or (row.RowState <> DataRowState.Deleted AndAlso IsDBNull(row("Create_Update"))) Then
                                row("Create_Update") = Now
                                If IsDBNull(row("Owner")) Then row("Owner") = clsApplicationSettings.UserName
                            End If

                            'if record was added, autoincrement the RecID
                            If row.RowState = DataRowState.Added Then
                                row("RecID") = NextRecID
                                NextRecID += 1
                            End If
                        Next

                        If MainForm IsNot Nothing Then MainForm.WriteProgress(String.Format("Updating {0} records in {1}; please stand by...", dtBrowser.GetChanges.Rows.Count, MyTableName), ProgressBarStyle.Marquee, False)

                        Me.Enabled = False

                        frmJournal.AddJournalEntry(MyTableName, frmJournal.enumJournalEntry.Edit, dtBrowser.GetChanges.Rows.Count)
                        Dim StartTime As Date = Now
                        Try
                            'daBrowser.ContinueUpdateOnError = True
                            Dim num As Integer = daBrowser.Update(dtBrowser)
                            dtBrowser.AcceptChanges()
                        Catch exc As DBConcurrencyException
                            ErrorMsg("Unable to update the table. Your edits could not be saved.", exc)
                            dtBrowser.RejectChanges()
                        End Try

                        If Now.Subtract(StartTime).TotalSeconds > 15 Then
                            frmInfoMsg.ShowInfoMsg("Edit in Grid", "Note: it took a long time to update the source table with your edits. You will get much better performance using 'Change/Delete/Convert Selected Records' commands on the Edit menu than making a large number of edits using 'Edit in Grid'.")
                        End If
                        Project.UpdateTrackingRecord(MyTableName, Project.GetRecordCount(MyTableName), True)
                        'MainForm.WriteProgress("Updating table; please stand by", ProgressBarStyle.Marquee, False)
                        'Project.UpdateOwnerField(MyTableName)
                        clsApplicationSettings.ResetEditTime()
                        Cancel = False
                    Case Windows.Forms.DialogResult.No
                        dtBrowser.RejectChanges()
                        Cancel = False
                    Case Windows.Forms.DialogResult.Cancel
                        Cancel = True
                End Select
            End If
        Catch ex As DBProviders.DbSqlException
            WarningMsg(ex.Message)
        Catch ex As Exception
            ErrorMsg(, ex)
        Finally
            Me.Enabled = True
            If MainForm IsNot Nothing Then MainForm.ProgressComplete()
            frmJournal.ClearJournalDescription()
        End Try
    End Sub

    Private Sub SetupForm()
        Try
            If MyTableType = clsProject.enumTableTypes.Temporary Then
                Text = "Opening selected data table..."
                MyFileName = MyTableName
                txtSQLString.Visible = True
                dgBrowser.Height = txtSQLString.Top - dgBrowser.Top * 2
                'parse sql string to only include the WHERE clause
                Dim LastSqlString As String = FormatSQL(clsApplicationSettings.GetKey(enumKey.LastQuerySQL, "No Prior SQL String!"))
                Dim i As Integer = LastSqlString.IndexOf("WHERE")
                If i = -1 Then
                    txtSQLString.Text = "All Data Selected"
                Else
                    txtSQLString.Text = StringFormat(LastSqlString).Replace(vbCr, vbCrLf)
                End If
                If Not Project.DB.ViewExists(clsProject.TempData) And Not Project.DB.TableExists(clsProject.TempData) Then
                    Text = "Selected Data"
                    txtSQLString.Text = "No data have been selected yet."
                    cboNumRecords.Enabled = False
                Else
                    cboNumRecords.Enabled = True
                End If
            Else
                SuspendLayout()
                txtSQLString.Visible = False
                dgBrowser.Height = btnClose.Top - dgBrowser.Top * 2
                Application.DoEvents()
                Text = "Opening table: " & TableName & "..."
                MyFileName = MyTableName
                ResumeLayout()
            End If
        Catch ex As Exception
            ErrorMsg(, ex)
            'Finally
            '    IniFile.SaveAndClose()
        End Try
    End Sub

    Friend Sub FillGrid()

        MainForm.WriteProgress("Loading data...")
        Application.DoEvents()

        SetupForm()

        With Project
            If Not (.DB.TableExists(MyTableName) OrElse Project.DB.ViewExists(MyTableName)) Then MainForm.ProgressComplete() : Exit Sub 'if try to display tempdata before you've queried will get error
            MainForm.WriteProgress("Getting record count")
            ResetMyTotalRecords()
            MainForm.ProgressComplete()
        End With

        MainForm.WriteProgress("Filling browser grid")
        UpdateComboBox(MyRecordCount)
        GetDataSource()
        FinishFillGrid()
    End Sub

    Friend Sub FillGridInBackground()
        SetupForm()
        If Not (Project.DB.TableExists(MyTableName) Or Project.DB.ViewExists(MyTableName)) Then MainForm.ProgressComplete() : Exit Sub 'if try to display tempdata before you've queried will get error
        Control.CheckForIllegalCrossThreadCalls = True
        MainForm.WriteProgress("Loading data...")
        UpdateComboBox(MyRecordCount)
        bwGetDataSource = New System.ComponentModel.BackgroundWorker
        With bwGetDataSource
            .WorkerSupportsCancellation = True
            dgBrowser.DataSource = Nothing
            .RunWorkerAsync()
        End With
    End Sub

    Public Function GetRecordCount() As Integer
        Return Project.GetRecordCount(MyTableName, IIf(ShowAllOwnerRecords, "", clsApplicationSettings.UserName), IIf(MyTableType = clsProject.enumTableTypes.Temporary, clsApplicationSettings.UserName, ""))
    End Function

    Public Function GetEditableRecordCount() As Integer
        Return Project.GetRecordCount(MyTableName, IIf(ShowAllOwnerRecords And Project.IsLoggedIn, "", clsApplicationSettings.UserName), IIf(MyTableType = clsProject.enumTableTypes.Temporary, clsApplicationSettings.UserName, ""))
    End Function

    Public Function GetSelectedRecordCount() As Integer
        Return Project.GetRecordCount(clsProject.TempData, IIf(ShowAllOwnerRecords, "", clsApplicationSettings.UserName), clsApplicationSettings.UserName)
    End Function

    Private Sub GetDataSource()
        Try
            ' set up connection string
            Dim j As Int16 = MyFileName.LastIndexOf("\")
            MyTableFile = MyFileName.Substring(j + 1)
            'MyTableName = MyTableFile.Replace(".DB", "").Replace(".db", "")

            With Project
                'if table has BLOB fields, show them
                HasBlob = .DB.GetColumnList(FullTableName).Contains("OBJECT_TYPE")

                ' set up SQL statement
                Dim sql As String
                Dim fldlist As String = "Dta.Station_ID,Dta.Date_Time,Dta.PCode,Dta.LEW_Pct,Dta.Depth_M,Dta.Agency,Dta.CCode,Dta.SCode,Dta.LCode,Dta.QCode,Dta.RCode,Dta.Result,Dta.Validated,Dta.Track_ID"
                If ShowAllOwnerRecords Then fldlist &= ",Dta.Owner"
                If HasBlob Then fldlist &= ",Dta.Object_Type,Dta.Object_Value"
                fldlist &= ",PCodes.Sig_Figs AS Sig_Figs"

                'if displaying selected data, only show records selected by current user
                Dim WhereOwner_SelectedBy As String = ""

                If ShowAllOwnerRecords And (Not AllowEditing Or Project.IsLoggedIn) Then
                    If MyTableType = clsProject.enumTableTypes.Temporary Then
                        WhereOwner_SelectedBy = String.Format("WHERE Selected_By = '{0}'", clsApplicationSettings.UserName)
                    End If
                Else
                    WhereOwner_SelectedBy = String.Format("WHERE (Owner = '{0}' OR Owner IS NULL)", clsApplicationSettings.UserName)
                    If MyTableType = clsProject.enumTableTypes.Temporary Then
                        WhereOwner_SelectedBy &= String.Format(" AND Selected_By = '{0}'", clsApplicationSettings.UserName)
                    End If
                End If

                'if only showing selected records, include criteria here
                Dim WhereSelect As String = ""
                If SqlString.Contains("WHERE") Then WhereSelect = SqlString.Substring(SqlString.IndexOf("WHERE") + 6)

                Dim WhereString As String = WhereOwner_SelectedBy
                If WhereSelect <> "" Then WhereString &= IIf(WhereString = "", "WHERE ", " AND ") & WhereSelect

                fldlist = "Dta.RecID,Dta.Station_ID,Dta.Date_Time,Dta.PCode,Dta.LEW_Pct,Dta.Depth_M,Dta.Agency,Dta.CCode,Dta.SCode,Dta.LCode,Dta.QCode,Dta.RCode,Dta.Result,Dta.Validated,Dta.Track_ID,Dta.Owner,Dta.Create_Update"

                'if want data to be sorted, add order now
                Dim OrderBy As String = ""
                If lstSortFields.Count > 0 Then
                    OrderBy = "ORDER BY " & ArrayToCSV(lstSortFields)
                End If

                If MaxRecords = -1 Then
                    sql = String.Format("SELECT {1} FROM {0} Dta {2}", .DB.AddBrackets(FullTableName), fldlist, WhereString)
                Else
                    Select Case .DB.DatabaseType
                        Case clsDB.enumDBType.Firebird, clsDB.enumDBType.Firebird_Embedded
                            sql = String.Format("SELECT FIRST {1} {2} FROM {0} Dta {3} {4}", .DB.AddBrackets(FullTableName), MaxRecords, fldlist, WhereString, OrderBy)
                        Case clsDB.enumDBType.SQLite, clsDB.enumDBType.MySQL
                            sql = String.Format("SELECT {2} FROM {0} Dta {3} {4} LIMIT {1}", .DB.AddBrackets(FullTableName), MaxRecords, fldlist, WhereString, OrderBy)
                        Case clsDB.enumDBType.Oracle
                            sql = String.Format("SELECT {2} FROM {0} Dta {3} {4} ROWNUM<={1} {5}", .DB.AddBrackets(FullTableName), MaxRecords, fldlist, WhereString, IIf(WhereString = "", "WHERE", "AND"), OrderBy)
                        Case Else
                            sql = String.Format("SELECT TOP {1} {2} FROM {0} Dta {3} {4}", .DB.AddBrackets(FullTableName), MaxRecords, fldlist, WhereString, OrderBy)
                    End Select
                End If

                ' retrieve data into DataTable
                daBrowser = .DB.AddTableadapter(dtBrowser, sql)
                Try
                    .SetTableHeadings(dtBrowser)
                Catch ex As Exception
                    WarningMsg(ex.Message)
                End Try

            End With
        Catch ex As System.OutOfMemoryException
            ErrorMsg("You have tried to load more records than will fit in memory; select fewer records or narrow your selection.", ex)
            dtBrowser.Clear()
        Catch ex As Exception
            ErrorMsg(, ex)
        End Try
    End Sub

    Friend Sub SetCaption()
        Select Case MyTableType
            Case clsProject.enumTableTypes.Working
                Dim DisplayName As String = MyTableName
                Text = String.Format("{0} [{1} Table]", DisplayName, "Working")
                If Project.DB.DatabaseType = clsDB.enumDBType.Paradox AndAlso Not Project.DB.IsTableIndexed(MyTableName) Then Text &= " (Legacy Format)"
            Case clsProject.enumTableTypes.Master
                Text = String.Format("{0} [{1} Table]", MyTableName, "Master")
                If MainForm.AllowEditMaster Then Text &= " (Editing Allowed)"
                If Project.DB.DatabaseType = clsDB.enumDBType.Paradox AndAlso Not Project.DB.IsTableIndexed(MyTableName) Then Text &= " (Legacy Format)"
            Case clsProject.enumTableTypes.Temporary
                Text = String.Format("Selected from {0} at {1} ({2})", clsApplicationSettings.GetKey(enumKey.LastQueryTable, ""), MyCDate(clsApplicationSettings.GetKey(enumKey.LastQueryTime, "1/1/1900")).ToString(MyDateTimeFormat), Choose(Project.QueryOption + 1, "View", "Table", "Subquery"))
            Case clsProject.enumTableTypes.HiddenData
                If Not MyTableName.StartsWith(clsProject.TempPrefix) Then
                    Text = String.Format("{0} [{1} Table]", TestNull(MyFormCaption, MyTableName), "External")
                End If
        End Select
    End Sub

    Public Sub SetCaption(FormCaption As String)
        MyFormCaption = FormCaption
        SetCaption()
    End Sub

    Private Sub FinishFillGrid()
        Try
            SetCaption()
            If MyAllowEditing Then Text &= EditCaption

            MainForm.WriteProgress("Filling grid with data")

            If dgBrowser Is Nothing Then Exit Sub

            With dgBrowser
                .SuspendLayout()
                '.DataSource = Nothing
                .Font = New Font("Tahoma", 8, FontStyle.Regular, GraphicsUnit.Point)
                .AllowUserToOrderColumns = False
                .AllowUserToResizeColumns = True
                .AllowUserToResizeRows = False
                If MyAllowEditing Then
                    .AllowUserToDeleteRows = True
                    .AllowUserToAddRows = True
                    .RowHeadersVisible = True
                    '.AutoResizeRowHeadersWidth(DataGridViewRowHeadersWidthSizeMode.AutoSizeToAllHeaders)
                    .ReadOnly = False
                    .SelectionMode = DataGridViewSelectionMode.CellSelect
                Else
                    .AllowUserToDeleteRows = False
                    .AllowUserToAddRows = False
                    .RowHeadersVisible = False
                    .ReadOnly = True
                    .SelectionMode = DataGridViewSelectionMode.FullRowSelect
                End If

                .ColumnHeadersBorderStyle = DataGridViewHeaderBorderStyle.Single
                .StandardTab = False

                If dtBrowser Is Nothing Then Exit Sub

                'reset filter string
                If FilterString = "" Then
                    .DataSource = dtBrowser
                Else
                    Dim bs As New BindingSource(dtBrowser, "")
                    bs.Filter = FilterString
                    dgBrowser.DataSource = bs
                End If

                Dim hiddenfields As New Generic.List(Of String)(New String() {"RECID", "CREATE_UPDATE", "DTA.RECID", "DTA.CREATE_UPDATE"})

                For c As Int16 = 0 To .ColumnCount - 1
                    With .Columns(c)
                        .HeaderText = dtBrowser.Columns(c).Caption
                        .SortMode = DataGridViewColumnSortMode.NotSortable
                        If dtBrowser.Columns(c).DataType Is GetType(String) Then
                            .DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleLeft
                        ElseIf dtBrowser.Columns(c).DataType Is GetType(Boolean) Then
                            .DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter
                        ElseIf dtBrowser.Columns(c).DataType Is GetType(Date) Then
                            .DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleLeft
                            .DefaultCellStyle.Format = MyDateTimeFormat()
                        Else
                            .DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleRight
                            If Not MyAllowEditing Then
                                If .HeaderText = "Result" Then
                                    .DefaultCellStyle.Format = "N3" 'note: may be overridden using PCode's Sig_Figs value in CellFormatting event
                                ElseIf .HeaderText = "Trk ID" Or .HeaderText = "Val" Then
                                    .DefaultCellStyle.Format = "N0"
                                Else
                                    .DefaultCellStyle.Format = "N2" 'depth and LEW
                                End If
                            End If
                        End If

                        If hiddenfields.Contains(.Name.ToUpper) Then .Visible = False

                        'cannot just fill combobox with items from support table, because would get an error if table contained
                        'a value not found in the support table and it would automatically get changed; instead, add all values
                        'in support table and all unique values found in data table that were not in the support table

                        Dim SupportTable As String = "", KeyField As String = "", FieldName As String = ""
                        Select Case .Name.ToUpper
                            Case "STATION_ID" : SupportTable = "Stations" : KeyField = "Station_ID"
                            Case "PCODE" : SupportTable = "PCodes" : KeyField = "PCode"
                            Case "AGENCY" : SupportTable = "Agencies" : KeyField = "Agency"
                            Case "CCODE" : SupportTable = "CCodes" : KeyField = "CCode"
                            Case "LCODE" : SupportTable = "Validation" : KeyField = "LCode" : FieldName = "Valid_Value"
                            Case "SCODE" : SupportTable = "Validation" : KeyField = "SCode" : FieldName = "Valid_Value"
                            Case "QCODE" : SupportTable = "QCodes" : KeyField = "QCode"
                            Case "RCODE" : SupportTable = "RCodes" : KeyField = "RCode"
                            Case "VALIDATED" : .ReadOnly = False
                            Case "TRACK_ID" : .ReadOnly = True
                        End Select

                        If MyAllowEditing Then

                            If .Visible AndAlso SupportTable <> "" AndAlso mnuOptionsDropdowns.Checked Then
                                Dim lstSupt As Generic.List(Of String) = Nothing
                                If FieldName = "" Then 'normal query
                                    lstSupt = Project.DB.GetRecordList(SupportTable, KeyField)
                                Else 'query validation table
                                    lstSupt = Project.DB.GetRecordList(SupportTable, FieldName, String.Format("WHERE Field_Name='{0}'", KeyField))
                                End If
                                If lstSupt.Count < 5000 AndAlso MyRecordCount < 1000000 Then 'if list is too large, really slows down and may cause out of memory error
                                    If ItemIn(c, 6, 7, 10, 11) Then lstSupt.Add("")
                                    Dim lstData As Generic.List(Of String) = Project.DB.GetRecordList(FullTableName, KeyField)
                                    Dim AlreadySep As Boolean = False
                                    For Each s As String In lstData
                                        If Not lstSupt.Contains(s) Then
                                            If Not AlreadySep Then lstSupt.Add("(Not in Support Table:)") : AlreadySep = True
                                            lstSupt.Add(s)
                                        End If
                                    Next
                                    dgvBrowser.SetColumnFormat(WRDB.Controls.DGVEditor.enumColumnTypes.ComboBox, c, lstSupt)
                                End If
                            End If
                        Else
                            If SupportTable <> "" And dgBrowser.Rows.Count > 0 Then dgvBrowser.SetColumnFormat(DGVEditor.enumColumnTypes.None, c)
                        End If
                    End With
                    'Application.DoEvents()
                Next

                If .Columns.Contains("OWNER") Then .Columns("OWNER").Visible = ShowAllOwnerRecords
                If .Columns.Contains("dta.OWNER") Then .Columns("dta.OWNER").Visible = ShowAllOwnerRecords

                'cannot display blob column properly in grid; add a link column for object type to perform operations

                For c As Integer = .Columns.Count - 1 To 0 Step -1
                    If .Columns(c).Name = "Object_Type" Then
                        dgvBrowser.SetColumnFormat(WRDB.Controls.DGVEditor.enumColumnTypes.Link, c)
                        .Columns(c).DefaultCellStyle.NullValue = "<Attach>"
                    ElseIf .Columns(c).Name = "Object_Value" Then
                        .Columns.RemoveAt(c)
                    End If
                Next

                .EditMode = DataGridViewEditMode.EditOnKeystrokeOrF2  'want to be able to do global editing (double-click to enter is OK)
                dgvBrowser.AutoFillSelectedCells = True

                .ColumnHeadersDefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter
                .ColumnHeadersDefaultCellStyle.WrapMode = DataGridViewTriState.False
                .AutoResizeColumns(DataGridViewAutoSizeColumnsMode.DisplayedCells)
                '.RowHeadersWidth = 43
                'make form just wide enough to show data
                .ResumeLayout(True)

                If .Rows.Count > 0 Then ClientSize = New Size(IIf(.RowHeadersVisible, .RowHeadersWidth, 0) + .Columns.GetColumnsWidth(DataGridViewElementStates.Visible) + SystemInformation.VerticalScrollBarWidth + .Left * 2 + 5, Me.ClientSize.Height)

                MainForm.ProgressComplete()

            End With

            dgvBrowser.AutoFillSelectedCells = False

            UpdateComboBox(MyRecordCount)

            If MyTableType <> clsProject.enumTableTypes.Temporary Then MainForm.StatusBarPanelText.Text = String.Format("{0:N0} records from {1} are displayed", MyNumRecords, MyFileName)

            'If Not WRDBForms.Contains(Text.Replace(EditCaption, "")) Then WRDBForms.Add(Me, Text.Replace(EditCaption, ""))
            Dim key As String
            If TableType = clsProject.enumTableTypes.Temporary Then key = "Temporary" Else key = TableName
            If Not WRDBForms.Contains(key) Then WRDBForms.Add(Me, key)

            MainForm.EnableBrowserMenus()

            'note: the Find and Filter buttons can be confusing for novice users (since only apply to records loaded in browser)
            'Dim ShowButtons As Boolean = (cboNumRecords.SelectedIndex = cboNumRecords.Items.Count - 1)
            'btnOptions.Enabled = ShowButtons

            'If IsMWForm And TableType <> clsProject.enumTableTypes.Temporary Then CType(MainForm, frmMainMW).ResetAll()

            'with WRDB 6 shared ownership of tables, warn user if no records are visible because they are all owned by other people
            If dtBrowser.Rows.Count = 0 AndAlso MyRecordCount > 0 AndAlso Not ShowAllOwnerRecords AndAlso Project.IsLoggedIn Then
                Select Case frmSelectOption.SelectOption(Me, "Why is this table empty?", String.Format("This browser for data table ({0}) is empty because you don't own any of the records in the shared table (based on your user name of {1}). There are actually a total of {2:N0} records owned by other people that are not being displayed.", MyTableName, clsApplicationSettings.UserName, Project.GetTrackingRecordCount(MyTableName)), "Always do this action for the remainder of this session", "Temporarily show all records regardless of ownership", "Permanently claim ownership of all the records in the table", "Just display the empty browser")
                    Case frmSelectOption.enumResult.Button1 : MainForm.mnuEditShowAll.PerformClick()
                    Case frmSelectOption.enumResult.Button2 : MainForm.mnuEditResetOwner.PerformClick()
                    Case frmSelectOption.enumResult.Button3
                End Select
            End If
        Catch ex As Exception
            ErrorMsg(, ex)
        Finally
            'IniFile.SaveAndClose()
            MainForm.ProgressComplete()
        End Try
    End Sub

    ''' <summary>
    ''' Will scan for ownership of records and report if some or all are not owned by current user
    ''' </summary>
    Public Sub CheckRecordOwnership()
        If dtBrowser.Rows.Count > 0 AndAlso MyRecordCount > 0 AndAlso Not ShowAllOwnerRecords AndAlso Project.IsLoggedIn Then
            Dim lst As Generic.List(Of String) = Project.DB.GetRecordList(MyTableName, "Owner")
            For Each o As String In lst
                If o <> clsApplicationSettings.UserName Then
                    Select Case frmSelectOption.SelectOption(
                        Me,
                        "Not all records belong to you",
                        $"This browser for data table ({MyTableName}) may appear to be missing some records because you don't own all of the records in the shared table (based on your user name of {clsApplicationSettings.UserName}). There are actually a total of {Project.GetTrackingRecordCount(MyTableName) - dtBrowser.Rows.Count:N0} records owned by other people that are not being displayed.",
                        "Always do this action for the remainder of this session",
                        "Temporarily show all records regardless of ownership",
                        "Permanently claim ownership of all the records in the table",
                        "Just display the your records in the browser")
                        Case frmSelectOption.enumResult.Button1 : MainForm.mnuEditShowAll.PerformClick()
                        Case frmSelectOption.enumResult.Button2 : MainForm.mnuEditResetOwner.PerformClick()
                        Case frmSelectOption.enumResult.Button3
                    End Select
                    Exit Sub
                End If
            Next
        End If
    End Sub

    Private Sub UpdateComboBox(NumRecords As Long)
        MyRecordCount = NumRecords
        With Me.cboNumRecords
            Dim LastIndex As Integer = .SelectedIndex
            .Items.Clear()
            Dim ar() As Integer = {1000, 5000, 10000, 25000, 50000}
            For i As Integer = 0 To 4
                Dim num As Integer = ar(i)
                If num >= NumRecords And NumRecords <> -1 Then Exit For
                .Items.Add(String.Format("Show first {0} records", num))
            Next
            If NumRecords = 0 Then
                .SelectedIndex = -1
                .Text = "No records " & IIf(MyTableType = clsProject.enumTableTypes.Temporary, "selected", "in table")
            Else
                If NumRecords = -1 Then
                    .Items.Add("Show all records")
                Else
                    .Items.Add(String.Format("Show all {0} records", NumRecords))
                End If
                .SelectedIndex = Min(.Items.Count - 1, Max(0, Min(.Items.Count - 1, LastIndex)))
            End If
            UpdateNumRecords()
        End With
    End Sub

    Private Sub UpdateNumRecords()
        If Not FillIsComplete Then Exit Sub
        With cboNumRecords
            Dim txt As String = .Text
            If Val(txt) <> 0 Then 'a number was typed in
                .Text = String.Format("Show first {0} records", Val(txt))
            ElseIf txt.StartsWith("Show all records") Then
                txt = -1
            Else
                Dim ar() As String = txt.Split(" ")
                If ar.Length >= 3 AndAlso Val(ar(2)) <> 0 Then
                    txt = ar(2)
                Else
                    .SelectedIndex = IIf(.Items.Count = 0, -1, 0)
                    txt = "1000"
                End If
            End If
            'note: the Find and Filter buttons can be confusing for novice users (since only apply to records loaded in browser)
            'Dim ShowButtons As Boolean = (.SelectedIndex = .Items.Count - 1)
            'btnOptions.Enabled = ShowButtons

            MaxRecords = Val(txt.Replace(",", "").Replace(".", "")) 'different number styles may use periods as separators
            dgBrowser.Focus()
        End With
    End Sub

    ''' <summary>
    ''' Return number of records visible in grid
    ''' </summary>
    Friend ReadOnly Property MyNumRecords() As Long
        Get
            If dgBrowser Is Nothing Then Return 0 Else Return dgBrowser.Rows.Count
        End Get
    End Property

    ''' <summary>
    ''' Return number or records in table
    ''' </summary>
    Friend ReadOnly Property MyTotalRecords() As Long
        Get
            Return MyRecordCount
        End Get
    End Property

    ''' <summary>
    ''' Reset record count for table (as in after query)
    ''' </summary>
    Friend Sub ResetMyTotalRecords()
        MyRecordCount = -1
        If MyTableType <> clsProject.enumTableTypes.Temporary Then MyRecordCount = Project.GetTrackingRecordCount(MyTableName)

        If Project.DisplayRecordCount <> clsProject.enumDisplayRecordCount.Never AndAlso MyRecordCount = -1 Then
            If MyTableType = clsProject.enumTableTypes.Temporary OrElse Project.DisplayRecordCount = clsProject.enumDisplayRecordCount.Always Then
                Dim sw As New Stopwatch : sw.Start()
                MyRecordCount = GetRecordCount()
                If sw.Elapsed.Seconds >= RecordCountTimeout Then MainForm.CheckRecordCountWarning(Project)
                If MyTableType <> clsProject.enumTableTypes.Temporary Then Project.UpdateTrackingRecord(MyTableName, MyRecordCount)
            End If
        End If
    End Sub

    Private Sub btnClose_Click(sender As Object, e As System.EventArgs) Handles btnClose.Click
        If FillIsComplete Then Me.Close()
    End Sub

    Private Sub frmBrowser_Activated(sender As Object, e As System.EventArgs) Handles MyBase.Activated

        If Me.MdiParent Is Nothing Then Me.ShowInTaskbar = True

        If TableType = clsProject.enumTableTypes.Temporary Then Exit Sub

        If IsMWForm And Me IsNot ActiveBrowser Then
            'ActiveBrowser = Me
            'If MainForm IsNot Nothing AndAlso FillIsComplete AndAlso TableType <> clsProject.enumTableTypes.Temporary Then CType(MainForm, frmMainMW).ResetAll() 'when first loaded is not yet initialized
        Else
            ActiveBrowser = Me
        End If
        If MainForm IsNot Nothing Then
            MainForm.mnuEditGrid.Checked = MyAllowEditing
            mnuOptionsEdit.Checked = MyAllowEditing
        End If
    End Sub

    Private Sub bwGetDataSource_DoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs) Handles bwGetDataSource.DoWork
        FillIsComplete = False
        GetDataSource()
        'If MyTableType = clsProject.enumTableTypes.Working Then
        '    MyRecordCount = Project.GetTrackingRecordCount(MyTableName)
        'Else
        '    MyRecordCount = Project.DB.GetRecordCount(MyTableName)
        'End If
        ResetMyTotalRecords()
        If CType(sender, System.ComponentModel.BackgroundWorker).CancellationPending Then e.Cancel = True
    End Sub

    Private Sub bwGetDataSource_RunWorkerCompleted(sender As Object, e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles bwGetDataSource.RunWorkerCompleted
        If Not e.Cancelled Then
            FinishFillGrid()
            bwGetDataSource.Dispose()
            bwGetDataSource = Nothing
        End If
        FillIsComplete = True
    End Sub

    Private Sub frmBrowser_DragDrop(sender As Object, e As System.Windows.Forms.DragEventArgs) Handles MyBase.DragDrop
        For i As Integer = 0 To e.Data.GetData(DataFormats.FileDrop).length - 1
            MainForm.EditImportFile(e.Data.GetData(DataFormats.FileDrop)(i))
        Next
    End Sub

    Private Sub frmBrowser_DragEnter(sender As Object, e As System.Windows.Forms.DragEventArgs) Handles MyBase.DragEnter
        If e.Data.GetDataPresent(DataFormats.FileDrop) Then
            Dim FileName As String = e.Data.GetData(DataFormats.FileDrop)(0)
            Select Case IO.Path.GetExtension(FileName).ToUpper
                Case ".DB", ".DBF", ".MDB", ".XLS", ".XLSX", ".XLSM", ".TXT", ".CSV", ".RDB", ".BMD", ".BMD2", ".DSS", ".WDM", ".OUT", ".AIR"
                    e.Effect = DragDropEffects.Copy
                Case Else
                    e.Effect = DragDropEffects.None
            End Select
        End If
    End Sub

    Private Sub frmBrowser_FormClosed(sender As Object, e As System.Windows.Forms.FormClosedEventArgs) Handles MyBase.FormClosed
        Try
            CloseSelectedRecordsBrowser()
            SaveSetting(REGAPP, Me.Name, mnuOptionsDropdowns.Name, mnuOptionsDropdowns.Checked)

            ProgressCancel = True
            If bwGetDataSource IsNot Nothing Then
                With bwGetDataSource
                    .CancelAsync()
                    Do
                        Application.DoEvents()
                        Threading.Thread.Sleep(100)
                    Loop Until Not .IsBusy
                    .Dispose()
                End With
                bwGetDataSource = Nothing
            End If
            MyDataReader = Nothing
            If dgBrowser IsNot Nothing Then dgBrowser.Dispose()
            dgBrowser = Nothing
            With Project
                If dtBrowser IsNot Nothing Then dtBrowser.Clear() : dtBrowser.Dispose()
                If .DB IsNot Nothing AndAlso .DB.Connection IsNot Nothing Then .DB.Connection.Close()
            End With

            'If WRDBForms.Contains(Text.Replace(EditCaption, "")) Then WRDBForms.Remove(Text.Replace(EditCaption, ""))

            Dim key As String
            If TableType = clsProject.enumTableTypes.Temporary Then key = "Temporary" Else key = TableName
            If WRDBForms.Contains(key) Then WRDBForms.Remove(key)

            ActiveBrowser = Nothing

            If MainForm IsNot Nothing Then
                MainForm.EnableBrowserMenus()

                'If IsMWForm And TableType <> clsProject.enumTableTypes.Temporary Then
                '    If WRDBForms.Count = 0 And MainForm IsNot Nothing Then CType(MainForm, frmMainMW).ResetAll() 'otherwise, activate of other browser will do reset
                '    SaveWindowPos(REGAPP, Me)
                '    'convenient means to remove menu handlers so don't have to have so many methods
                '    For Each item As ToolStripItem In mnuMain.Items
                '        RemoveMenuHandler(item)
                '    Next
                'End If
                MainForm.ProgressComplete()
            End If
        Catch ex As Exception
            ErrorMsg(, ex)
        End Try
    End Sub

    'Private Sub frmBrowser_KeyPress(sender As Object, e As System.Windows.Forms.KeyPressEventArgs) Handles Me.KeyPress
    '    If Me.bwGetDataSource IsNot Nothing Then
    '        If e.KeyChar = Chr(27) Then AskCancel()
    '        If ProgressCancel Then
    '            With bwGetDataSource
    '                .CancelAsync()
    '                Do
    '                    Application.DoEvents()
    '                Loop Until Not .IsBusy
    '                .Dispose()
    '                bwGetDataSource = Nothing
    '            End With
    '            'Project.DataSet.Tables.Remove(TableName)
    '            If Project.DB.Connection IsNot Nothing AndAlso Project.DB.Connection.State = ConnectionState.Open Then Project.DB.Connection.Close()
    '            WriteProgress(True)
    '            Me.Close()
    '        End If
    '    End If
    'End Sub

    ''' <summary>
    ''' This is no longer being used--using advanced query feature now to select records
    ''' </summary>
    ''' <remarks></remarks>
    Private Sub FilterRecords()
        Try
            If Not FillIsComplete Then Exit Sub
            With New frmFilter
                .DataGrid = Me.dgBrowser
                .txtFilterString.Text = FilterString
                .ShowDialog(Me)
                FilterString = .txtFilterString.Text
                .Dispose()
                MainForm.StatusBarPanelText.Text = String.Format("{0:N0} records from {1} are displayed", MyNumRecords, MyFileName)
            End With
        Catch ex As Exception
            ErrorMsg(, ex)
        End Try
    End Sub

    Private Sub btnOptions_Click(sender As System.Object, e As System.EventArgs) Handles btnOptions.Click
        With btnOptions
            mnuOptions.Show(btnOptions, New Point(.Width / 2, .Height / 2))
        End With
    End Sub

    Private Sub cboNumRecords_KeyDown(sender As Object, e As System.Windows.Forms.KeyEventArgs) Handles cboNumRecords.KeyDown
        'note: cannot get it to avoid beeping when press enter!
        If e.KeyCode = Keys.Enter Then
            e.Handled = True
            e.SuppressKeyPress = True
            UpdateNumRecords()
            FillGridInBackground()
        End If
    End Sub

    Private Sub cboNumRecords_SelectedIndexCommitted(sender As Object, e As System.EventArgs) Handles cboNumRecords.SelectionChangeCommitted
        'text doesn't get changed immediately--force it
        With cboNumRecords
            .Text = .Items(.SelectedIndex)
        End With
        UpdateNumRecords()
        FillGridInBackground()
    End Sub

    Private Sub frmBrowser_FormClosing(sender As Object, e As System.Windows.Forms.FormClosingEventArgs) Handles MyBase.FormClosing
        Dim Cancel As Boolean = False
        SaveEdits(Cancel)
        If Cancel Then e.Cancel = True
    End Sub

    Private Sub frmBrowser_KeyPress(sender As Object, e As KeyPressEventArgs) Handles Me.KeyPress
        ''when type decimal point, like Excel always replace with comma if that is what is dictated by culture setting
        'If e.KeyChar = "." And Globalization.CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator = "," Then
        '    e.KeyChar = Globalization.CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator
        'End If
    End Sub

    Private Sub frmBrowser_Load(sender As Object, e As System.EventArgs) Handles MyBase.Load
        mnuOptionsDropdowns.Checked = GetSetting(REGAPP, Me.Name, mnuOptionsDropdowns.Name, True)

        'Control.CheckForIllegalCrossThreadCalls = False
        dgvBrowser = New WRDB.Controls.DGVEditor(dgBrowser, MainWRDB.GridFont, Project.ReportScaling, PrintDoc)

        If MainForm.IsMdiContainer Then
            mnuMain.Visible = False
            tbMain.Visible = False
            'add handler for options context menu
            For Each item As ToolStripItem In mnuOptions.Items
                If TypeOf item Is ToolStripMenuItem Then AddMenuHandler(item)
            Next
        Else
            mnuMain.Visible = True
            tbMain.Visible = True
            'convenient means to add menu handlers so don't have to have so many methods
            For Each item As ToolStripItem In mnuMain.Items
                AddMenuHandler(item)
            Next
            'add handler for options context menu
            For Each item As ToolStripItem In mnuOptions.Items
                If TypeOf item Is ToolStripMenuItem Then AddMenuHandler(item)
            Next
            'replace Help button with minimize/maximize buttons more suitable for SDI application
            Me.HelpButton = False
            Me.MinimizeBox = True
            Me.MaximizeBox = True
            Me.tbWhatsThis.Visible = False
            Me.mnuHelpWhatsThis.Visible = False
        End If

        'fill dictionary from PCodes table so can format display of Result
        Dim dr As DbDataReader = Project.DB.ExecuteReader($"SELECT PCode,Sig_Figs FROM {Project.FullTableName(clsProject.enumTableTypes.PCodes)} WHERE PCode IS NOT NULL AND Sig_Figs IS NOT NULL")
        While dr IsNot Nothing AndAlso (Project.DB.DatabaseType <> clsDB.enumDBType.SQL_Server_CE AndAlso dr.HasRows) AndAlso dr.Read
            dictSigFigs.Add(dr.GetString(0), dr.GetValue(1))
        End While
        dr.Close()

        EnableBrowserMenus()
    End Sub

    Private Sub dgvEditor_ProgressChanged(sender As Object, e As ProgressEventArgs) Handles dgvBrowser.ProgressChanged
        If Not MainForm.WriteProgress(e.Percent, 100, "Processing request...", ProgressBarStyle.Blocks, True) Then dgvBrowser.CancelOperation()
    End Sub

    Private Sub dgvEditor_ProgressComplete(sender As Object) Handles dgvBrowser.ProgressComplete
        MainForm.ProgressComplete()
    End Sub

    Private Sub btnHelp_Click(sender As Object, e As System.EventArgs) Handles btnHelp.Click
        ShowHelp(Me, "2")
    End Sub


#Region "Menu Responses"

    ''' <summary>
    ''' This recursive routine allows me to place all menu handling routines in a single method
    ''' Dropdownitemclicked event is not equivalent; the menu stayed visible after the response started
    ''' </summary>
    Private Sub AddMenuHandler(item As ToolStripMenuItem)
        AddHandler item.Click, AddressOf mnu_Click
        For Each subitem As ToolStripItem In item.DropDownItems
            If TypeOf subitem Is ToolStripMenuItem Then AddMenuHandler(subitem)
        Next
    End Sub

    ''' <summary>
    ''' This recursive routine allows me to place all menu handling routines in a single method
    ''' Dropdownitemclicked event is not equivalent; the menu stayed visible after the response started
    ''' </summary>
    Private Sub RemoveMenuHandler(item As ToolStripMenuItem)
        RemoveHandler item.Click, AddressOf mnu_Click
        For Each subitem As ToolStripItem In item.DropDownItems
            If TypeOf subitem Is ToolStripMenuItem Then RemoveMenuHandler(subitem)
        Next
    End Sub

    ''' <summary>
    ''' Select Case to call methods in response to menu clicks
    ''' </summary>
    Private Sub mnu_Click(sender As Object, e As System.EventArgs)
        Try

            If Not FillIsComplete Then Exit Sub 'do not allow any actions until background fill action is complete

            Dim menuName As String = CType(sender, ToolStripMenuItem).Name

            'even though menu is disabled, shortcut key can cause a response, so trap that here

            If menuName.StartsWith("mnuEdit") AndAlso Not (mnuEdit.Enabled And mnuEdit.Visible) Then Exit Sub
            If menuName.StartsWith("mnuSelect") AndAlso Not (mnuSelect.Enabled And mnuSelect.Visible) Then Exit Sub
            If menuName.StartsWith("mnuOutput") AndAlso Not (mnuOutput.Enabled And mnuOutput.Visible) Then Exit Sub

            With MainForm
                Select Case menuName
                    Case mnuFileExit.Name : Me.Close()

                    Case mnuEditGrid.Name, mnuOptionsEdit.Name : .EditGrid()
                    Case mnuEditCopy.Name, mnuOptionsCopy.Name : .EditCopy()
                    Case mnuEditPaste.Name, mnuOptionsPaste.Name : .EditPaste()
                    Case mnuEditDelete.Name : .EditDeleteRecords(ActiveTableName)
                    Case mnuEditDeleteAll.Name : .EditDelete()
                    Case mnuEditChange.Name : .EditChangeRecords(ActiveTableName)
                    Case mnuEditImportFile.Name : .EditImportFile()
                    Case mnuEditImportLSPC.Name : .EditImportLSPC(False)
                    Case mnuEditAppend.Name : .EditAppend()
                    Case mnuEditValidate.Name : .EditValidate()
                    Case mnuEditTransfer.Name : .EditTransfer()
                    Case mnuEditInfo.Name, mnuOptionsInfo.Name : .EditTableInfo(ActiveTableName)
                    Case mnuEditCount.Name, mnuOptionsCount.Name : .EditCountRecords()
                    Case mnuOptionsDropdowns.Name : If FillIsComplete AndAlso MyAllowEditing Then .EditGrid() : .EditGrid() : FillGridInBackground() 'save edits first
                    Case mnuOptionsAppend.Name : dgBrowser.CurrentCell = dgBrowser.Item(1, dgBrowser.Rows.Count - 1)
                    Case mnuOptionsDelete.Name : If dgBrowser.CurrentCellAddress.Y >= 0 Then dgBrowser.Rows.RemoveAt(dgBrowser.CurrentCellAddress.Y) : dgvBrowser.IsModified = True
                    Case mnuOptionsSort.Name : .EditSort()
                        'Case mnuOptionsFilter.Name : FilterRecords() 'no longer using this--use select instead
                    Case mnuOptionsFilter.Name : .EditSelect()
                    Case mnuOptionsRefresh.Name : .EditRefresh()
                    Case mnuOptionsShowAll.Name : .EditShowAll()

                    Case mnuCalcNew.Name : .EditCalcNew()
                    Case mnuCalcAggregate.Name : .EditCalcAggregate()
                    Case mnuCalcDOSat.Name : .EditCalcDO()
                    Case mnuCalcLoad.Name : .EditCalcLoad()
                    Case mnuCalcTSI.Name : .EditCalcTSI()
                    Case mnuCalcLowFlow.Name : .EditCalcLowFlow()

                    Case mnuSelectAll.Name : .SelectAll()
                    Case mnuSelectRanges.Name : .SelectRanges()
                    Case mnuSelectAdvanced.Name : .SelectAdvanced()
                    Case mnuSelectSQL.Name : .SelectSQL()
                    Case mnuSelectDisplay.Name : .SelectDisplay()
                    Case mnuSelectSavePrevious.Name : .SelectSavePrevious()
                    Case mnuSelectEdit.Name : .SelectEdit()
                    Case mnuSelectDelete.Name : .SelectDelete()

                    Case mnuExportFile.Name : .OutputExport(ActiveBrowser.TableName)
                    Case mnuExportMultFiles.Name : .OutputExportMult(ActiveBrowser.TableName)
                    Case mnuExportLSPC.Name : .OutputLSPC(ActiveBrowser.TableName)
                    Case mnuOutputSave.Name : .OutputSave()

                    Case mnuRptStaPCode.Name : .OutputReport(frmMain.enumReportType.SumStaPCode)
                    Case mnuRptPCodeSta.Name : .OutputReport(frmMain.enumReportType.SumPCodeSta)
                    Case mnuRptCCodePCodeSta.Name : .OutputReport(frmMain.enumReportType.SumCCodePCodeSta)
                    Case mnuRptSta.Name : .OutputReport(frmMain.enumReportType.SumSta)
                    Case mnuRptPCode.Name : .OutputReport(frmMain.enumReportType.SumPCode)
                    Case mnuRptCCode.Name : .OutputReport(frmMain.enumReportType.SumCCode)
                    Case mnuRptStats.Name : .OutputReport(frmMain.enumReportType.SumStats)
                    Case mnuRptCompStats.Name : .OutputReport(frmMain.enumReportType.SumCompStats)
                    Case mnuRptSortSta.Name : .OutputReport(frmMain.enumReportType.SortSta)
                    Case mnuRptSortPCode.Name : .OutputReport(frmMain.enumReportType.SortPCode)
                    Case mnuRptSortCCode.Name : .OutputReport(frmMain.enumReportType.SortCCode)
                    Case mnuRptSortDate.Name : .OutputReport(frmMain.enumReportType.SortDate)
                    Case mnuRptScreenLab.Name : .OutputReport(frmMain.enumReportType.ScreenLab)
                    Case mnuRptScreenCrit.Name : .OutputReport(frmMain.enumReportType.ScreenCrit)

                    Case mnuGraphTS.Name : .OutputGraph(Graph.enumGraphType.TimeSeries)
                    Case mnuGraphLong.Name : .OutputGraph(Graph.enumGraphType.Profile)
                    Case mnuGraphDepth.Name : .OutputGraph(Graph.enumGraphType.Depth)
                    Case mnuGraphWidth.Name : .OutputGraph(Graph.enumGraphType.Width)
                    Case mnuGraphScatter.Name : .OutputGraph(Graph.enumGraphType.Scatter)
                    Case mnuGraphProb.Name : .OutputGraph(Graph.enumGraphType.Probability)
                    Case mnuGraphFlowDuration.Name : .OutputGraph(Graph.enumGraphType.FlowDuration)
                    Case mnuGraphFreq.Name : .OutputGraph(Graph.enumGraphType.Histogram)

                    Case mnuHelpContents.Name : .HelpContents()
                    Case mnuHelpWhatsThis.Name : VB6.WhatsThisMode(Me)
                    Case mnuHelpTechSupport.Name : .HelpTechSupport()
                    Case mnuHelpUpdates.Name : MainWRDB.UpdatesInstalled(True)
                    Case mnuHelpWeb.Name : .HelpWebSite()
                    Case mnuHelpVersion.Name : .HelpVersion()
                    Case mnuHelpAbout.Name : .HelpAbout()
                End Select
            End With
        Catch ex As Exception
            ErrorMsg(, ex)
        End Try
    End Sub

    ''' <summary>
    ''' Select Case to call methods in response to toolbar clicks
    ''' </summary>
    Private Sub tbMain_ItemClicked(sender As Object, e As System.Windows.Forms.ToolStripItemClickedEventArgs) Handles tbMain.ItemClicked
        If Not FillIsComplete Then Exit Sub
        Application.DoEvents()
        Select Case CType(sender, ToolStrip).Items.IndexOf(e.ClickedItem) + 10
            Case 10 : Me.mnuSelectAll.PerformClick()
            Case 11 : Me.mnuSelectRanges.PerformClick()
            Case 12 : Me.mnuSelectAdvanced.PerformClick()
            Case 13 : Me.mnuSelectSQL.PerformClick()
            Case 14 'saved query combo
            Case 15 : Me.mnuSelectDisplay.PerformClick()
            Case 16
            Case 17 : Me.mnuRptStaPCode.PerformClick()
            Case 18 : Me.mnuRptSta.PerformClick()
            Case 19 : Me.mnuRptPCode.PerformClick()
            Case 20
            Case 21 : Me.mnuGraphTS.PerformClick()
            Case 22 : Me.mnuGraphScatter.PerformClick()
            Case 23 'Me.mnuOutputGIS.PerformClick()
            Case 25
            Case 26 : Me.mnuEditImportFile.PerformClick()
            Case 27 : Me.mnuEditDelete.PerformClick()
            Case 28 : Me.mnuOutputExport.PerformClick()
            Case 29 : Me.mnuOutputSave.PerformClick()
            Case 30
            Case 31 : Me.mnuHelpWhatsThis.PerformClick()
            Case 32 : Me.mnuHelpContents.PerformClick()
        End Select
    End Sub

    Private Sub tbSavedSQL_DropDown(sender As Object, e As System.EventArgs) Handles tbSavedSQL.DropDown
        If Not mnuSelect.Enabled Then Exit Sub
        With tbSavedSQL.Items
            .Clear()
            For Each s As String In My.Computer.FileSystem.GetFiles(modCommon.TestNull(Project.SQLDir, MyDataPath), FileIO.SearchOption.SearchTopLevelOnly, "*.sql")
                Dim sqlname As String = IO.Path.GetFileNameWithoutExtension(s)
                If sqlname = sqlname.ToLower Then sqlname = Proper(sqlname)
                .Add(sqlname)
            Next
        End With
    End Sub

    Private Sub tbSavedSQL_SelectedIndexChanged(sender As Object, e As System.EventArgs) Handles tbSavedSQL.SelectedIndexChanged
        If Not mnuSelect.Enabled Or tbSavedSQL.SelectedIndex = -1 Then Exit Sub
        Application.DoEvents()
        MainForm.SelectSaved(tbSavedSQL.SelectedItem)
        tbSavedSQL.SelectedIndex = -1
    End Sub

    Public Sub EnableBrowserMenus()
        Dim EnableWorking As Boolean = Not Text Like "*Master*"
        mnuEdit.Visible = EnableWorking
        tbImportFile.Enabled = EnableWorking
        tbDeleteSelected.Enabled = EnableWorking
        mnuOptionsAppend.Enabled = EnableWorking
        mnuOptionsDelete.Enabled = EnableWorking
        mnuOptionsEdit.Enabled = EnableWorking
        mnuOptionsInfo.Enabled = EnableWorking
        mnuOptionsPaste.Enabled = EnableWorking
    End Sub

    Private Sub mnuSelectSaved_DropDownOpening(sender As Object, e As System.EventArgs) Handles mnuSelectSaved.DropDownOpening
        If Not mnuSelect.Enabled Then Exit Sub
        With mnuSelectSaved.DropDownItems
            For i As Integer = .Count - 1 To 4 Step -1
                .RemoveAt(i)
            Next
            For Each s As String In My.Computer.FileSystem.GetFiles(modCommon.TestNull(Project.SQLDir, MyDataPath), FileIO.SearchOption.SearchTopLevelOnly, "*.sql")
                .Add(IO.Path.GetFileNameWithoutExtension(s))
            Next
        End With
    End Sub

    Private Sub mnuSelectSaved_DropDownItemClicked(sender As Object, e As System.Windows.Forms.ToolStripItemClickedEventArgs) Handles mnuSelectSaved.DropDownItemClicked
        'this is not great because menu doesn't disappear immediately
        If Not mnuSelect.Enabled Then Exit Sub
        Application.DoEvents()
        Select Case e.ClickedItem.Name
            Case mnuSelectEdit.Name 'handled above
            Case mnuSelectDelete.Name 'handled above
            Case mnuSelectSavePrevious.Name
            Case Else
                MainForm.SelectSaved(CType(e.ClickedItem, ToolStripMenuItem).Text)
        End Select
    End Sub

#End Region

    Private Sub dgBrowser_CellContentClick(sender As Object, e As System.Windows.Forms.DataGridViewCellEventArgs) Handles dgBrowser.CellContentClick
        'if is displaying blob entry, show context menu
        With dgBrowser
            If .Columns(e.ColumnIndex).Name = "Object_Type" And .Columns(e.ColumnIndex).GetType Is GetType(DataGridViewLinkColumn) Then
                Dim pt As Point
                With .GetCellDisplayRectangle(e.ColumnIndex, e.RowIndex, True)
                    pt = New Point(.Left + .Width / 2, .Top + .Height / 2)
                End With
                ContextMenuObject.Show(dgBrowser, pt)
            End If
        End With
    End Sub

    Private Sub dgBrowser_RowValidating(sender As Object, e As System.Windows.Forms.DataGridViewCellCancelEventArgs) Handles dgBrowser.RowValidating
        With dgBrowser
            If Not AllowEditing Then Exit Sub
            .Rows(e.RowIndex).ErrorText = ""
            Dim lstReqdFields As New Generic.List(Of String)(New String() {"STATION_ID", "DATE_TIME", "PCODE"})
            If .Columns.Contains("Station_ID") AndAlso TestNull(.Item("Station_ID", e.RowIndex).FormattedValue, "") = "" OrElse
               .Columns.Contains("Date_Time") AndAlso TestNull(.Item("Date_Time", e.RowIndex).FormattedValue, "") = "" OrElse
               .Columns.Contains("PCode") AndAlso TestNull(.Item("PCode", e.RowIndex).FormattedValue, "") = "" OrElse
               .Columns.Contains("RCode") AndAlso TestNull(.Item("RCode", e.RowIndex).FormattedValue, "") = "" AndAlso
               .Columns.Contains("Result") AndAlso TestNull(.Item("Result", e.RowIndex).FormattedValue, "") = "" Then
                .Rows(e.RowIndex).ErrorText = "You must enter values for the Station ID, Date-Time, PCode, and RCode and/or Result columns."
                'If e.RowIndex <> .NewRowIndex Then e.Cancel = True
            End If

        End With
    End Sub

    Private Sub dgBrowser_CellFormatting(sender As Object, e As System.Windows.Forms.DataGridViewCellFormattingEventArgs) Handles dgBrowser.CellFormatting
        'If Project.DB.DatabaseType = clsDB.enumDBType.SQL_Server Then 'for some reason, does not obey datagridview nullvalue setting
        '    If e.ColumnIndex >= 0 AndAlso dgBrowser.Item(e.ColumnIndex, e.RowIndex).Value.isnull Then e.Value = "" : e.FormattingApplied = True
        'End If
        If e.ColumnIndex < 0 Then Exit Sub
        With dgBrowser
            If .Columns(e.ColumnIndex).Name = "Result" And Not MyAllowEditing Then
                'Dim SigFigs As Object = .Item("Sig_Figs", e.RowIndex).Value
                'If IsNumeric(SigFigs) Then e.CellStyle.Format = "N" & CInt(SigFigs)
                Dim SigFigs As Integer = 3
                If .Columns.Contains("PCode") Then
                    Dim PCode As String = TestNull(.Item("PCode", e.RowIndex).Value, "")
                    If Not dictSigFigs.TryGetValue(PCode, SigFigs) Then SigFigs = 3
                    e.CellStyle.Format = "N" & CInt(SigFigs)
                End If
            End If
        End With
    End Sub

    Private Sub dgBrowser_CellValidated(sender As Object, e As System.Windows.Forms.DataGridViewCellEventArgs) Handles dgBrowser.CellValidated
        'convert to upper case if string
        If dgBrowser.Columns(e.ColumnIndex).ValueType = GetType(String) AndAlso
           TestNull(dgBrowser.Item(e.ColumnIndex, e.RowIndex).Value, "") <> TestNull(dgBrowser.Item(e.ColumnIndex, e.RowIndex).Value, "").ToString.ToUpper Then
            dgBrowser.Item(e.ColumnIndex, e.RowIndex).Value = dgBrowser.Item(e.ColumnIndex, e.RowIndex).Value.ToString.ToUpper
        End If
    End Sub

    Private Sub mnuOptionsFind_Click(sender As Object, e As System.EventArgs) Handles mnuOptionsFind.Click
        Try
            If Not FillIsComplete Then Exit Sub
            With New frmFind
                .DataGrid = Me.dgBrowser
                .Show(Me)
            End With
        Catch ex As Exception
            ErrorMsg(, ex)
        End Try
    End Sub

    Private Sub mnuOptions_Opening(sender As Object, e As System.ComponentModel.CancelEventArgs) Handles mnuOptions.Opening
        Dim tf As Boolean = (MainForm.AllowEditMaster Or TableType = clsProject.enumTableTypes.Working) AndAlso (Project.IsLoggedIn OrElse Not Project.IsReadOnly)
        mnuOptionsEdit.Enabled = tf
        mnuOptionsInfo.Enabled = tf
        mnuOptionsPaste.Enabled = tf
        mnuOptionsAppend.Enabled = tf
        mnuOptionsDelete.Enabled = tf
        mnuOptionsShowAll.Enabled = MyTableType <> clsProject.enumTableTypes.Temporary
        mnuOptionsShowAll.Checked = ShowAllOwnerRecords
    End Sub

    Private Sub btnApply_Click(sender As System.Object, e As System.EventArgs) Handles btnApply.Click
        MainForm.EditGrid()
    End Sub

    Private Sub mnuObject_Click(sender As Object, e As System.EventArgs) Handles mnuObjectDisplay.Click, mnuObjectImportFile.Click, mnuObjectPasteTimeSeries.Click, mnuObjectRemove.Click, mnuObjectSaveAs.Click, mnuObjectImportTimeSeries.Click, mnuObjectProperties.Click
        Try
            With dgBrowser
                Dim dt As DataTable = dgBrowser.DataSource
                Dim ext As String = TestNull(.Item("Object_Type", .CurrentRow.Index).Value, "")
                Dim ObjType As clsBlob.enumObjectType = clsBlob.ObjectType(ext)
                Dim BaseDate As Date = TestNull(.CurrentRow.Cells("Date_Time").Value, Date.MinValue)

                If sender Is mnuObjectDisplay Then
                    Dim FileName As String = ""
                    Dim blob() As Byte = dt.Rows(dgBrowser.CurrentRow.Index)("Object_Value")
                    FileName = String.Format("{0}\WRDB{1}.{2}", clsProject.TempPath, .CurrentRow.Index, ext)
                    clsBlob.SaveBlob(ext, FileName, blob, BaseDate)
                    Process.Start(FileName)

                ElseIf sender Is mnuObjectImportFile Then
                    With New OpenFileDialog
                        .CheckFileExists = True
                        .Filter = "All Files (*.*)|*.*"
                        .InitialDirectory = GetSetting(REGAPP, Me.Name, "Directory")
                        .Multiselect = False
                        .Title = "Attach File"
                        If .ShowDialog(Me) = Windows.Forms.DialogResult.OK Then
                            Dim FileExt As String = IO.Path.GetExtension(.FileName).Replace(".", "").ToUpper
                            dgBrowser.CurrentCell.Value = FileExt
                            dt.Rows(dgBrowser.CurrentRow.Index)("Object_Value") = clsBlob.LoadBlob(clsBlob.enumObjectType.File, .FileName)
                            SaveSetting(REGAPP, Me.Name, "Directory", IO.Path.GetDirectoryName(.FileName))
                        End If
                        .Dispose()
                    End With

                ElseIf sender Is mnuObjectImportTimeSeries Then
                    With New OpenFileDialog
                        .CheckFileExists = True
                        .Filter = "Time Series Files (*.txt)|*.txt"
                        .InitialDirectory = GetSetting(REGAPP, Me.Name, "Directory")
                        .Multiselect = False
                        .Title = "Attach Time Series File"
                        If .ShowDialog(Me) = Windows.Forms.DialogResult.OK Then
                            Try
                                Dim NumRec As Integer = 0
                                ObjType = clsBlob.enumObjectType.ValueSeries 'always try to load as constant-step series first
                                dt.Rows(dgBrowser.CurrentRow.Index)("Object_Value") = clsBlob.LoadBlob(ObjType, .FileName, BaseDate, NumRec)
                                dgBrowser.CurrentCell.Value = clsBlob.ObjectName(ObjType)
                                WarningMsgFmt("A total of {0:N0} time series records were added to this record.", NumRec)
                            Catch ex As Exception
                                Throw
                            End Try
                            SaveSetting(REGAPP, Me.Name, "Directory", IO.Path.GetDirectoryName(.FileName))
                        End If
                        .Dispose()
                    End With

                ElseIf sender Is mnuObjectPasteTimeSeries Then
                    Dim Msg As String = "You must place time series data in the clipboard formatted in multiple rows of two tab- or comma-separated columns comprised of date-time and result values or a single column or result values (you will be prompted to specify the time step)."
                    If BaseDate = Date.MinValue Then
                        WarningMsg("You must enter a valid date-time before you can import time series data.")
                        Exit Try
                    End If
                    If My.Computer.Clipboard.ContainsText Then
                        'write text in clipboard to text file then load that
                        Dim text As String = My.Computer.Clipboard.GetText
                        Dim FileName As String = clsProject.TempPath & "\Clipboard.txt"
                        Dim NumRec As Integer = 0

                        Try
                            If Not (text.Contains(vbTab) Or text.Contains(",")) Then 'assume is single column of result values
                                Dim s As String = InputBox("The clipboard appears to contain a single column of result values; please enter the desired constant time step in seconds:", "Paste Time Series")
                                If s = "" Or Not IsNumeric(s) Then Exit Sub
                                Dim sw As New IO.StreamWriter(FileName)
                                sw.WriteLine("Date_Time" & vbTab & "Result")
                                text = text.Replace(vbCrLf, vbCr)
                                Dim arLine() As String = text.Split(vbCr)
                                For i As Integer = 0 To arLine.Length - 2
                                    sw.WriteLine(StringFormat("{0:yyyy-MM-dd HH:mm:ss}\t{1}", BaseDate.AddSeconds(s * i), arLine(i)))
                                Next
                                sw.Close()
                                sw.Dispose()
                                ObjType = clsBlob.enumObjectType.ValueSeries
                                dt.Rows(dgBrowser.CurrentRow.Index)("Object_Value") = clsBlob.LoadBlob(ObjType, FileName, BaseDate, NumRec)
                                dgBrowser.CurrentCell.Value = clsBlob.ObjectName(ObjType)
                            Else
                                If Not text.StartsWith("Date_Time", StringComparison.OrdinalIgnoreCase) Then text = "Date_Time" & vbTab & "Result" & vbCr & text
                                My.Computer.FileSystem.WriteAllText(FileName, text, False)
                                dt.Rows(dgBrowser.CurrentRow.Index)("Object_Value") = clsBlob.LoadBlob(clsBlob.enumObjectType.TimeSeries, FileName, BaseDate, NumRec)
                                dgBrowser.CurrentCell.Value = clsBlob.ObjectName(clsBlob.enumObjectType.TimeSeries)
                            End If
                            WarningMsgFmt("A total of {0:N0} time series records were added to this record.", NumRec)
                        Catch ex As Exception
                            Throw
                        End Try
                    Else
                        WarningMsg(Msg)
                    End If

                ElseIf sender Is mnuObjectSaveAs Then
                    Select Case ObjType
                        Case clsBlob.enumObjectType.TimeSeries, clsBlob.enumObjectType.ValueSeries : ext = "TXT"
                    End Select
                    With New SaveFileDialog
                        .AddExtension = True
                        .DefaultExt = ext
                        .InitialDirectory = GetSetting(REGAPP, Me.Name, "Directory")
                        .OverwritePrompt = True
                        .SupportMultiDottedExtensions = False
                        .Title = "Save Attachment As File"
                        .Filter = String.Format("{0} Files (*.{1})|*.{1}", ext, ext.ToLower)
                        If .ShowDialog(Me) = Windows.Forms.DialogResult.OK Then
                            Dim blob() As Byte = dt.Rows(dgBrowser.CurrentRow.Index)("Object_Value")
                            clsBlob.SaveBlob(ObjType, .FileName, blob, BaseDate)
                            SaveSetting(REGAPP, Me.Name, "Directory", IO.Path.GetDirectoryName(.FileName))
                        End If
                        .Dispose()
                    End With

                ElseIf sender Is mnuObjectRemove Then
                    If WarningMsgFmt("Are you sure you want to permanently remove the {0} attachment from the table?", ext) = Windows.Forms.DialogResult.OK Then
                        With dt.Rows(dgBrowser.CurrentRow.Index)
                            .Item("Object_Type") = DBNull.Value
                            .Item("Object_Value") = DBNull.Value
                        End With
                    End If

                ElseIf sender Is mnuObjectProperties Then
                    If IsDBNull(dt.Rows(dgBrowser.CurrentRow.Index)("Object_Value")) Then Exit Sub
                    Dim blob() As Byte = dt.Rows(dgBrowser.CurrentRow.Index)("Object_Value")
                    Dim msg As String = ""
                    Select Case ObjType
                        Case clsBlob.enumObjectType.File
                            msg = StringFormat("Attachment Type: {0}\nFile Size: {1:N} KB", ext, blob.Length / 1024.0)
                        Case clsBlob.enumObjectType.TimeSeries
                            msg = StringFormat("Attachment Type: {0}\nFile Size: {1:N} KB\nNumber of variable-step time series records: {2}", ext, blob.Length / 1024.0, blob.Length / 8)
                        Case clsBlob.enumObjectType.ValueSeries
                            msg = StringFormat("Attachment Type: {0}\nFile Size: {1:N} KB\nNumber of constant-step time series records: {2}", ext, blob.Length / 1024.0, (blob.Length - 4) / 4)
                    End Select
                    MessageBox.Show(msg, "Attachment Properties", MessageBoxButtons.OK, MessageBoxIcon.Information)
                End If
            End With
        Catch ex As Exception
            ErrorMsg(, ex)
        End Try
    End Sub

    Private Sub ContextMenuObject_Opening(sender As Object, e As System.ComponentModel.CancelEventArgs) Handles ContextMenuObject.Opening
        'note: normally viewer is read-only, but for testing can try all menu items (but changes are not saved in table)
        With dgBrowser
            Dim ext As String = TestNull(.Item("Object_Type", .CurrentRow.Index).Value, "")
            mnuObjectDisplay.Enabled = ext <> ""
            mnuObjectSaveAs.Enabled = ext <> ""
            mnuObjectRemove.Enabled = ext <> "" And Not .ReadOnly
            'cannot set blob when editing new row because datatable row does not exist yet
            Dim IsNewRow As Boolean = dgBrowser.CurrentRow.Index > CType(dgBrowser.DataSource, DataTable).Rows.Count - 1
            mnuObjectImportFile.Enabled = Not .ReadOnly And Not IsNewRow
            mnuObjectImportTimeSeries.Enabled = Not .ReadOnly And Not IsNewRow
            mnuObjectPasteTimeSeries.Enabled = Not .ReadOnly And Not IsNewRow
            mnuObjectProperties.Enabled = ext <> ""
        End With
    End Sub

    'Private Sub mnuOptionsShowAll_Click(sender As Object, e As System.EventArgs) Handles mnuOptionsShowAll.Click
    '    ShowAllOwnerRecords = Not ShowAllOwnerRecords
    '    mnuOptionsShowAll.Checked = ShowAllOwnerRecords
    '    clsApplicationSettings.ResetEditTime()
    '    'FillGrid()
    '    ResetMyTotalRecords()
    '    UpdateComboBox(MyRecordCount)
    '    UpdateNumRecords()
    '    FillGridInBackground()
    'End Sub

    Private Sub btnJournal_Click(sender As Object, e As System.EventArgs) Handles btnJournal.Click
        frmJournal.GetJournalDescription()
    End Sub

End Class
